package com.ljw.security.springsecurity_springboot.controller;


import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;

/**
 * @FileName LoginController
 * @Description TODO    基于springsecurity+springboot的认证、授权
 * @Author ljw
 * @Date 2020/8/31 23:58
 * @Version 1.0
 */
@RestController
public class LoginController {

    /**
     * springsecurity的认证成功后跳转路径
     *
     * @return
     */
    @PostMapping(value = "/login-success", produces = {"text/plain;charset=utf-8"})
    public String loginSuccess() {
        String username = getUsername();
        return username+"登录成功";
    }

    /*** 匿名资源0 * @return */
    @PreAuthorize(value = "isAnonymous() or isAuthenticated()")//匿名或认证用户都可访问
    @GetMapping(value = "/n/n0", produces = {"text/plain;charset=utf-8"})
    public String r0() {
        String username = getUsername();
        return username+" 访问匿名资源0";
    }

    /*** 测试资源1 * @return */
    @PreAuthorize(value = "isAuthenticated() and hasAuthority('p1') and hasAuthority('p2')")//必须得认证，然后用户同时有p1、p2权限才可访问该方法，总经理、管理员
    @GetMapping(value = "/r/r1", produces = {"text/plain;charset=utf-8"})
    public String r1() {
        String username = getUsername();
        return username+" 访问资源1";
    }

    /*** 测试资源2 * @return */
    @PreAuthorize(value = "isAuthenticated() and hasAnyAuthority('p1','p2')")//必须得认证，然后用户有p1、p2中的任意一个权限即可访问该方法，总经理、管理员，员工A
    @GetMapping(value = "/r/r2", produces = {"text/plain;charset=utf-8"})
    public String r2() {
        String username = getUsername();
        return username+" 访问资源2";
    }


    /**
     * 获取当前登录用户名
     *      1.spring security提供会话管理，认证通过后，spring security自动将身份信息放入SecurityContextHolder上下文，
     *          SecurityContext与当前线程进行绑定，方便获取 用户身份。
     *      2. Spring Security获取当前登录用户信息的方法为SecurityContextHolder.getContext().getAuthentication()
     * @return
     */
    public String getUsername() {
        //Spring Security获取当前登录用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (!authentication.isAuthenticated()){
            return "匿名用户";
        }
        //获取当前登录用户的身份信息（org.springframework.security.core.userdetails.User类型，包含用户名、权限、密码（null））
        Object principal = authentication.getPrincipal();

        System.out.println("principal类型："+principal.getClass()+"====="+(principal instanceof UserDetails));

        String username;
        if (principal instanceof UserDetails){
            //用户名
            username = ((UserDetails) principal).getUsername();
            //密码
            String password = ((UserDetails) principal).getPassword();
            //权限
            Collection<? extends GrantedAuthority> authorities = ((UserDetails) principal).getAuthorities();

            for (GrantedAuthority authority : authorities) {
                String s = authority.getAuthority();
                System.out.println("username:"+username+"   password:"+password+"   authority:"+s);
            }

        }else {
            username=principal.toString();//访问匿名资源，username = anonymousUser
        }
        return username;
    }
}
